package com.heima.wemedia.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.heima.article.client.ArticleFeign;
import com.heima.common.aliyun.GreenImageUploadScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.delayTask.RedisDelayedQueueUtil;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.exception.LeadException;
import com.heima.common.util.BeanHelper;
import com.heima.common.util.JsonUtils;
import com.heima.common.util.SensitiveWordUtil;
import com.heima.file.service.MinioService;
import com.heima.model.media.dtos.WmNewsResultDTO;
import com.heima.wemedia.entity.WmNews;
import com.heima.wemedia.entity.WmSensitive;
import com.heima.wemedia.service.WmNewsAuditService;
import com.heima.wemedia.service.WmNewsService;
import com.heima.wemedia.service.WmSensitiveService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Slf4j
@Service
public class WmNewsAuditServiceImpl implements WmNewsAuditService , Serializable {

    @Autowired
    private GreenTextScan greenTextScan;

    @Autowired
    private WmNewsService wmNewsService;

    @Autowired
    private GreenImageUploadScan imageUploadScan;

    @Autowired
    private MinioService minioService;

    @Autowired
    private ArticleFeign articleFeign;

    @Autowired
    private RedisDelayedQueueUtil delayedQueueUtil;

    /**
     * 文章审核
     *
     * @param wmNews 自媒体文章
     */
    @Async("taskExecutor")  //异步操作注解
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void auditWmNews(WmNews wmNews) {
        log.info("=====子线程进行文章审核======");
        //检查文章状态,必须状态是 1-待审核
        if (wmNews.getStatus() != 1) {
            log.info("文章状态不是待审核,结束,id={}", wmNews.getId());
            return;
        }
        Integer wmNewsId=wmNews.getId();
        //获取文章 的文本内容(title.content) 和图片内容(content.images)
         Map<String,Object> map = getTextAndImage(wmNews);
        String text = (String) map.get("text");
        Set<String> urlSet = (Set<String>)map.get("image");
        //调用阿里云文本审核接口  ,如果审核不通过,改状态2,如果不确定改状态3
        boolean b = checkText(text,wmNewsId);
        if (!b) {
            log.info("文本检测未通过,结束");
            return;
        }
        //调用阿里云图片审核接口,如果审核不通过,改状态2,如果不确定改状态3
        if (!CollectionUtils.isEmpty(urlSet)) {
            boolean b1 = checkImage(urlSet,wmNewsId);
            if (!b1) {
                log.info("图片检测未通过,结束");
                return;
            }
        }

        //审核敏感词
        boolean b2 = checkSensitiveWorl(text,wmNewsId);
        if (!b2) {
            log.info("敏感词检测未通过,结束");
            return;
        }
        // 审核通过后,修改文章状态  8-审核通过,待发布
        updateWmNewsStatus(wmNewsId, 8, null, null);
        //判断是否到发布时间,如果没有到发布时间,结束
        Date publishTime = wmNews.getPublishTime();
        if (publishTime != null && System.currentTimeMillis() < publishTime.getTime()) {
            log.info("没有到发布时间，放入延迟任务，wmNewsId={}，pubtime={}", wmNewsId, publishTime);
            //计算延时时长
            long delayTime = publishTime.getTime() - System.currentTimeMillis();
            //把当前文章数据放入延迟队列
            delayedQueueUtil.addQueue(wmNewsId, delayTime, TimeUnit.MILLISECONDS, "wm.news.pub");
            log.info("wmNewsId={}，延迟时间 delay毫秒={}",wmNewsId,delayTime);
            log.info("没有到发布时间,结束");
            return;
        }
//        如果没有发布时间，或者当前时间大于发布时间，立即发布
        publishWmNews(wmNews,1);
    }

    /**
     * 发布文章
     * @param wmNews
     * @param type  1- 从审核方法调用，无需重新查询wmNews对象
     *              2- 从定时任务调用，需要重新查询wmNews对象
     */
    @Override
    public void publishWmNews(WmNews wmNews,int type) {
        Integer wmNewsId = wmNews.getId();
        if(type==2){
            wmNews = wmNewsService.getById(wmNewsId);
        }
        log.info("=======调用文章发布方法====");
        try {
//            对象属性拷贝
            WmNewsResultDTO newsResultDTO = BeanHelper.copyProperties(wmNews, WmNewsResultDTO.class);
//        发布自媒体文章，远程调用article服务
            Long articleId = articleFeign.saveArticle(newsResultDTO);
//        修改文章状态，9-已发布,文章发布id
            updateWmNewsStatus(wmNewsId, 9, "", articleId);
        }catch (Exception e){
            log.error("调用article服务，发布文章失败，wmNewsId={}",wmNewsId);
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }
    }

    @Autowired
    private WmSensitiveService wmSensitiveService;
    /**
     * 敏感词检测
     *
     * @param text
     * @return
     */
    private boolean checkSensitiveWorl(String text,Integer wmNewsId) {
        List<WmSensitive> list = wmSensitiveService.list();
        List<String> words = list.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
        Map<String, Integer> map = SensitiveWordUtil.matchWords(words, text);
        if (!CollectionUtils.isEmpty(map)) {
            //m敏感内容
            String reason = map.keySet().stream().collect(Collectors.joining(","));
            //有敏感词
            updateWmNewsStatus(wmNewsId, 2, reason, null);
            return false;
        }
        return true;
    }

    /**
     * 阿里云文本检测内容
     * @param text
     * @param wmNewsId
     * @return
     */
    private boolean checkText(String text,Integer wmNewsId) {
        if (StringUtils.isBlank(text)) {
            return true;
        }
        try {
            Map<String, String> map = greenTextScan.greenTextScan(text);
            if (CollectionUtils.isEmpty(map)) {
                log.error("阿里云文本检测,返回错误内容");
                throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
            }

            String suggestion = map.get("suggestion");
            String reason = map.get("reason");
            if ("pass".equals(suggestion)) {
                //检测通过
                log.info("文本检测通过!");
                return true;
            } else if ("review".equals(suggestion)) {
                //人工检测
                log.info("文本检测,需要人工审核!");
                //修改文章的 状态
                updateWmNewsStatus(wmNewsId, 3, reason,null);
                return false;
            } else {
                log.info("文本检测,审核不通过!");
                updateWmNewsStatus(wmNewsId, 2, reason,null);
                return false;
            }
        } catch (Exception e) {
            log.error("阿里云文本检测失败");
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }
    }

    /**
     * 阿里云图片检测内容
     * @param urlSet
     * @param wmNewsId
     * @return
     */
    private boolean checkImage(Set<String> urlSet,Integer wmNewsId) {
        if (!CollectionUtils.isEmpty(urlSet)) {
            return true;
        }
        try {
            List<byte[]> imageByte = new ArrayList<>();
            //从minio里面下载图片
            for (String url : urlSet) {
                byte[] bytes = minioService.downLoadFile(url);
                imageByte.add(bytes);
            }

            Map<String, String> map = imageUploadScan.imageScan(imageByte);
            if (CollectionUtils.isEmpty(map)) {
                log.error("阿里云文本检测,返回错误内容");
                throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
            }

            String suggestion = map.get("suggestion");
            String label = map.get("label");
            if ("pass".equals(suggestion)) {
                //检测通过
                log.info("图片检测通过!");
                return true;
            } else if ("review".equals(suggestion)) {
                //人工检测
                log.info("图片检测,需要人工审核!");
                //修改文章的 状态
                updateWmNewsStatus(wmNewsId, 3, label,null);
                return false;
            } else {
                log.info("图片检测,审核不通过!");
                updateWmNewsStatus(wmNewsId, 2, label,null);
                return false;
            }
        } catch (Exception e) {
            log.error("阿里云图片检测失败");
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }
    }
    /**
     * 修改文章状态
     * @param wmNewsId
     * @param status
     * @param reason
     */
    private void updateWmNewsStatus(Integer wmNewsId, int status, String reason,Long articleId) {
        WmNews wmNews = new WmNews();
        wmNews.setId(wmNewsId);
        wmNews.setStatus(status);
        if (StringUtils.isNotBlank(reason)) {
            wmNews.setReason(reason);
        }
        if (articleId != null) {
            wmNews.setArticleId(articleId);

        }
        wmNewsService.updateById(wmNews);
    }

    private Map<String, Object> getTextAndImage(WmNews wmNews) {
        //文本内容
        StringBuilder sbr = new StringBuilder();
        //图片内容url
        Set<String> urlSet = new HashSet<>();
        //文章内容
        String content = wmNews.getContent();

        List<Map<String, Object>> list = JsonUtils.nativeRead(content, new TypeReference<List<Map<String, Object>>>() {});
        //文本包括 title context
        sbr.append(wmNews.getTitle());
        if (StringUtils.isNotBlank(content)) {
        for (Map<String, Object> map : list) {
            String type = map.get("type").toString();
            String value = map.get("value").toString();
            if ("text".equals(type)) {
                //文本内容
                sbr.append(",").append(value);
            } else {
                //图片处理
                urlSet.add(value);
               }
            }
        }
        if (StringUtils.isNotBlank(wmNews.getImages())) {
            String[] urls = wmNews.getImages().split(",");
            urlSet.addAll(Arrays.asList(urls));
        }
        Map<String, Object> result = new HashMap<>();
        result.put("text", sbr.toString());
        result.put("image", urlSet);
        return result;
    }

}